﻿using System;
using System.IO;

using Microsoft.WindowsAzure;
using Microsoft.WindowsAzure.Storage;
using Microsoft.WindowsAzure.Storage.Blob;

using mvcForum.Core;
using mvcForum.Core.Helpers;
using mvcForum.Core.Interfaces;

namespace MvcForum.Hosting.Azure {

	/// <summary>
	/// Attachment storage provider using Azure blob storage.
	/// </summary>
	public class AttachmentStorage : IAttachmentStorage, IDisposable {
		private CloudBlobClient client;
		private CloudBlobContainer blobContainer;
		private const Int32 bufferSize = 4096;

		public AttachmentStorage(String container) {
			this.Configure(container);
		}

		private void Configure(String container) {
			CloudStorageAccount account = DirectoryResolver.GetAccount();

			// Get the client reference
			this.client = new CloudBlobClient(account.BlobEndpoint, account.Credentials);
			if (this.client == null) {
				throw new ArgumentException("credentials");
			}

			// Get the reference to the container
			this.blobContainer = this.client.GetContainerReference(container);

			// Create the container if it doesn't exist!
			if (this.blobContainer.CreateIfNotExists(BlobContainerPublicAccessType.Blob)) { }
		}

		/// <summary>
		/// Create an attachment from the input stream as a storage blob in Azure.
		/// </summary>
		/// <param name="attachment">Attachment object containing filename etc.</param>
		/// <param name="inputStream">The input stream of data for the attachment</param>
		/// <returns>The full path of the newly created attachment</returns>
		public String CreateAttachment(Attachment attachment, Stream inputStream, String contentType) {
			// Create the relative path of the blob.
			String path = String.Format("{0}/{1}", String.Join("/", PathHelper.GetPath(12, attachment.Post.Id)), attachment.Id);
			// Path and filename.
			String fullPath = String.Format("{0}/{1}", path, attachment.Filename);

			// Get the blob file.
			ICloudBlob file = this.blobContainer.GetBlockBlobReference(fullPath);
			// Set meta values
			file.Metadata["MetaName"] = "meta";

			try {
				file.UploadFromStream(inputStream);
				file.Properties.ContentType = contentType;
				file.SetProperties();
			}
			catch {
				// TODO:
			}

			// Let's return the full path of the blob.
			return String.Format("{0}/{1}", this.Root, path);
		}

		/// <summary>
		/// Delete the attachment in the blob storage.
		/// </summary>
		/// <param name="attachment">The attachment to delete.</param>
		public void DeleteAttachment(Attachment attachment) {
			// Let's create the relative path.
			String path = String.Format("{0}/{1}", String.Join("/", PathHelper.GetPath(12, attachment.Post.Id)), attachment.Id);
			// And full path, with filename.
			String fullPath = String.Format("{0}/{1}", path, attachment.Filename);

			// Get the blob file.
			ICloudBlob file = this.blobContainer.GetBlobReferenceFromServer(fullPath);
			// Delete it!
			file.DeleteIfExists();
		}

		/// <summary>
		/// Delete all attachments of the given post.
		/// </summary>
		/// <param name="post">The post that will have it's attachments delete.</param>
		public void DeleteAttachments(Post post) {
			// TODO: No way to delete by pattern on Azure???

			// Iterate all the attachments of the post.
			foreach (Attachment att in post.Attachments) {
				// Delete it!
				this.DeleteAttachment(att);
			}
		}

		/// <summary>
		/// The root of the Azure blob used for storage.
		/// </summary>
		public String Root {
			get {
				return this.blobContainer.Uri.ToString();
			}
		}

		public void Dispose() {
			this.client = null;
		}
	}
}